package top.laoshuzi.scad.mosinnagant.utils.ex

import eu.printingin3d.javascad.coords.Angles3d
import eu.printingin3d.javascad.coords.Coords3d
import eu.printingin3d.javascad.enums.Side
import eu.printingin3d.javascad.enums.Side.*
import eu.printingin3d.javascad.models.Abstract3dModel
import eu.printingin3d.javascad.tranzitions.*

//fun Tx(model: Abstract3dModel, x: Double): Abstract3dModel {
//    return model.run {
//        Translate(model, Coords3d.xOnly(x))
//    }
//}
//
//fun Ty(model: Abstract3dModel, y: Double): Abstract3dModel {
//    return model.run {
//        Translate(model, Coords3d.xOnly(y))
//    }
//}
//
//fun Tz(model: Abstract3dModel, z: Double): Abstract3dModel {
//    return model.run {
//        Translate(model, Coords3d.xOnly(z))
//    }
//}

fun Abstract3dModel.Sx(x: Double): Abstract3dModel {
    return this.run {
        Scale(this, Coords3d(x, 1.0, 1.0))
    }
}

fun Abstract3dModel.Sy(y: Double): Abstract3dModel {
    return this.run {
        Scale(this, Coords3d(1.0, y, 1.0))
    }
}

fun Abstract3dModel.Sz(z: Double): Abstract3dModel {
    return this.run {
        Scale(this, Coords3d(1.0, 1.0, z))
    }
}

fun Abstract3dModel.Sxyz(x: Double, y: Double, z: Double): Abstract3dModel {
    return this.run {
        Scale(this, Coords3d(x, y, z))
    }
}

fun Abstract3dModel.Tx(x: Double): Abstract3dModel {
    return this.run {
        Translate(this, Coords3d.xOnly(x))
    }
}

fun Abstract3dModel.Ty(y: Double): Abstract3dModel {
    return this.run {
        Translate(this, Coords3d.yOnly(y))
    }
}

fun Abstract3dModel.Tz(z: Double): Abstract3dModel {
    return this.run {
        Translate(this, Coords3d.zOnly(z))
    }
}

fun Abstract3dModel.Txyz(x: Double, y: Double, z: Double): Abstract3dModel {
    return this.run {
        Translate(this, Coords3d(x, y, z))
    }
}


fun Abstract3dModel.Rx(x: Double): Abstract3dModel {
    return rotate(Angles3d.xOnly(x))
}

fun Abstract3dModel.Ry(y: Double): Abstract3dModel {
    return rotate(Angles3d.yOnly(y))
}

fun Abstract3dModel.Rz(z: Double): Abstract3dModel {
    return rotate(Angles3d.zOnly(z))
}

fun Abstract3dModel.Rzyz(x: Double, y: Double, z: Double): Abstract3dModel {
    return rotate(Angles3d(x, y, z))
}

//fun List<Abstract3dModel>.intersection(): Abstract3dModel {
//    return Intersection(this)
//}
//
//fun List<Abstract3dModel>.union(): Abstract3dModel {
//    return Union(this)
//}
//
//fun List<Abstract3dModel>.difference(subtractedFrom: Abstract3dModel): Abstract3dModel {
//    return Difference(subtractedFrom, this)
//}

fun intersection(vararg subtracteds: Abstract3dModel): Abstract3dModel {
    return Intersection(subtracteds.toList())
}

fun union(vararg subtracteds: Abstract3dModel): Abstract3dModel {
    return Union(subtracteds.toList())
}

fun Abstract3dModel.difference(vararg subtracteds: Abstract3dModel): Abstract3dModel {
    return Difference(this, subtracteds.toList()).run { this }
}

fun Abstract3dModel.add(model: Abstract3dModel, side: Side = CENTER): Abstract3dModel {
    return addModelTo(side, model)
}

fun Abstract3dModel.addFront(model: Abstract3dModel, out: Boolean = true, center: Boolean = false): Abstract3dModel {
    return if (out) {
        if (center)
            addModelTo(FRONT_OUT_CENTER, model)
        else
            addModelTo(FRONT_OUT, model)
    } else {
        if (center)
            addModelTo(FRONT_IN_CENTER, model)
        else
            addModelTo(FRONT_IN, model)
    }
}

fun Abstract3dModel.addBack(model: Abstract3dModel, out: Boolean = true, center: Boolean = false): Abstract3dModel {
    return if (out) {
        if (center)
            addModelTo(BACK_OUT_CENTER, model)
        else
            addModelTo(BACK_OUT, model)
    } else {
        if (center)
            addModelTo(BACK_IN_CENTER, model)
        else
            addModelTo(BACK_IN, model)
    }
}

fun Abstract3dModel.addLeft(model: Abstract3dModel, out: Boolean = true, center: Boolean = false): Abstract3dModel {
    return if (out) {
        if (center)
            addModelTo(LEFT_OUT_CENTER, model)
        else
            addModelTo(LEFT_OUT, model)
    } else {
        if (center)
            addModelTo(LEFT_IN_CENTER, model)
        else
            addModelTo(LEFT_IN, model)
    }
}

fun Abstract3dModel.addRight(model: Abstract3dModel, out: Boolean = true, center: Boolean = false): Abstract3dModel {
    return if (out) {
        if (center)
            addModelTo(RIGHT_OUT_CENTER, model)
        else
            addModelTo(RIGHT_OUT, model)
    } else {
        if (center)
            addModelTo(RIGHT_IN_CENTER, model)
        else
            addModelTo(RIGHT_IN, model)
    }
}

fun Abstract3dModel.addTop(model: Abstract3dModel, out: Boolean = true, center: Boolean = false): Abstract3dModel {
    return if (out) {
        if (center)
            addModelTo(TOP_OUT_CENTER, model)
        else
            addModelTo(TOP_OUT, model)
    } else {
        if (center)
            addModelTo(TOP_IN_CENTER, model)
        else
            addModelTo(TOP_IN, model)
    }
}

fun Abstract3dModel.addBottom(model: Abstract3dModel, out: Boolean = true, center: Boolean = false): Abstract3dModel {
    return if (out) {
        if (center)
            addModelTo(BOTTOM_OUT_CENTER, model)
        else
            addModelTo(BOTTOM_OUT, model)
    } else {
        if (center)
            addModelTo(BOTTOM_IN_CENTER, model)
        else
            addModelTo(BOTTOM_IN, model)
    }
}
